← All Articles

[SW Expert Academy] 4013. 특이한 자석

Posted on

문제 :

엔지니어링 선표는 일을 하던 도중 창고에서 특이한 자석이 놓여있는 판을 발견했다.

이 판에는 4개의 자석이 놓여져 있었고, 각 자석은 8개의 ‘날’(튀어나온 곳)를 가지고 있다.

자석의 각 날 마다 N 극 또는 S 극의 자성을 가지고 있다.

이 특이한 자석은 [Fig. 1] 과 같이 1 번부터 4 번까지 판에 일렬로 배치되어 있고,

빨간색 화살표 위치에 날 하나가 오도록 배치되어 있다.

image

심심한 선표는 이 특이한 자석을 가지고 놀아보니 신기한 규칙을 발견했다.

임의의 자석을 1 칸씩 K 번 회전시키려고 해보니,

하나의 자석이 1 칸 회전될 때, 붙어 있는 자석은 서로 붙어 있는 날의 자성과 다를 경우에만 인력에 의해 반대 방향으로 1 칸 회전된다.

이를 신기하게 생각한 선표는 무작위로 자석을 돌렸을 때, 모든 회전이 끝난 후, 아래와 같은 방법으로 점수를 계산을 하고자 한다.

- 1 번 자석에서 빨간색 화살표 위치에 있는 날의 자성이 N 극이면 0 점, S 극이면 1 점을 획득한다.

- 2 번 자석에서 빨간색 화살표 위치에 있는 날의 자성이 N 극이면 0 점, S 극이면 2 점을 획득한다.

- 3 번 자석에서 빨간색 화살표 위치에 있는 날의 자성이 N 극이면 0 점, S 극이면 4 점을 획득한다.

- 4 번 자석에서 빨간색 화살표 위치에 있는 날의 자성이 N 극이면 0 점, S 극이면 8 점을 획득한다.

4 개 자석의 자성 정보와 자석을 1 칸씩 K 번 회전시키려고 할 때,

K 번 자석을 회전시킨 후 획득하는 점수의 총 합을 출력하는 프로그램을 작성하라.


[ 제약 사항 ]

  1. 시간제한 : 최대 50 개 테스트 케이스를 모두 통과하는 데 C / C++ / Java 모두 3 초
  2. 자석의 개수는 4 개이며, 각 자석은 8 개의 날을 가지고 있다.
  3. 자석을 회전시키는 횟수 K 는 1 이상 20 이하의 정수이다. ( 1 ≤ K ≤ 20 )
  4. 하나의 자석이 1 칸 회전될 때, 붙어 있는 자석은 서로 붙어 있는 날의 자성이 다를 경우에만 반대 방향으로 1 칸 회전된다.
  5. 자석을 회전시키는 방향은 시계방향이 1 로, 반시계 방향이 -1 로 주어진다.
  6. 날의 자성은 N 극이 0 으로, S 극이 1 로 주어진다.
  7. 각 자석의 날 자성정보는 빨간색 화살표 위치의 날부터 시계방향 순서대로 주어진다. 예를 들어, [Fig. 1] 의 1 번 자석의 자성정보는 0 0 1 0 0 1 0 0 과 같이 주어진다.

입력 :

입력의 맨 첫 줄에는 총 테스트 케이스의 개수 T 가 주어지고,

그 다음 줄부터 T 개의 테스트 케이스가 주어진다.

각 테스트 케이스의 첫 번째 줄에는 자석을 회전시키는 횟수 K 가 주어진다.

다음 4 개의 줄에는 1 번 자석부터 4 번 자석까지 각각 8 개 날의 자성정보가 차례대로 주어진다.

그 다음 K 개의 줄에는 자석을 1 칸씩 회전시키는 회전 정보가 주어진다.

자석의 회전 정보는 회전시키려는 자석의 번호, 회전방향으로 구성되어 있다.

회전방향은 1 일 경우 시계방향이며, -1 일 경우 반시계방향이다.


출력 :

테스트 케이스 개수만큼 T 개의 줄에 각각의 테스트 케이스에 대한 답을 출력한다.

각 줄은 “#t” 로 시작하고 공백을 하나 둔 다음 정답을 출력한다. ( t 는 1 부터 시작하는 테스트 케이스의 번호이다. )

정답은 모든 자석의 회전이 끝난 후 획득한 점수의 총 합이다.




풀이 :

톱니바퀴 형태로 생긴 특이한 자석 형태의 양극 정보를 배열로 나타내서 빨간 화살표가 있는 top 위치의 좌표를 움직여가면서 톱니바퀴가 마치 돌아가는 형식으로 코드를 구성하는 것이 키 포인트이다.

  • magnets[5][8] - 자석 4개의 극 정보를 담은 배열
  • toppos[5] - 빨간 화살표가 가리키고 있는 위치의 좌표 정보를 저장한 배열
  • currotate[5] - 한 번 특정 자석이 회전하였을 때 전체 자석들의 회전 정보를 저장한 배열

top 위치를 이동시켜 자석이 회전하는 것을 구현하기 위해서는 자석이 시계방향으로 회전 시 top 좌표를 -1, 반시계 방향으로 회전 시 top 좌표를 +1 해주는 방식으로 구현한다.

이렇게 한 번의 회전으로 각 자석들의 회전정보가 저장된 currotate 배열이 완성되면 toppos 배열에 더해주는 방식으로 회전 횟수를 모두 채워주면 최종 결과를 도출해낼 수 있다.




코드 :

코드 보기/접기
#include<iostream>
#include<cstring>
#include<cmath>

using namespace std;
int magnets[5][8], toppos[5], currotate[5];

void init() {
    memset(toppos, 0, sizeof(toppos));
}

int testCase() {
    init();

    int nums, magnetnum, rotatedir, answer = 0;

    cin >> nums;

    for (int i = 1; i <= 4; i++)
        for (int j = 0; j < 8; j++)
            cin >> magnets[i][j];

    while (nums--) {
        memset(currotate, 0, sizeof(currotate));
        cin >> magnetnum >> rotatedir;
        currotate[magnetnum] = rotatedir;

        for (int k = magnetnum; k > 1; k--) {
            if (magnets[k][(toppos[k] + 6) % 8] ==
                magnets[k - 1][(toppos[k - 1] + 2) % 8])
                break;
            currotate[k - 1] = (currotate[k] == 1) ? -1 : 1;
        }
        for (int k = magnetnum; k < 4; k++) {
            if (magnets[k][(toppos[k] + 2) % 8] ==
                magnets[k + 1][(toppos[k + 1] + 6) % 8])
                break;
            currotate[k + 1] = (currotate[k] == 1) ? -1 : 1;
        }

        for (int k = 1; k < 5; k++)
            toppos[k] = (toppos[k] - currotate[k] + 8) % 8;
    }

    for (int i = 1; i <= 5; i++)
        answer += pow(2, i - 1) * magnets[i][toppos[i]];
    return answer;
}

int main(int argc, char **argv) {
    int test_case, T;

    cin >> T;
    for (test_case = 1; test_case <= T; ++test_case)
        cout << '#' << test_case << ' ' << testCase() << '\n';

    return 0;
}


AlgorithmalgorithmSW ExpertC++